package per.vic.attachment.autoconfigure;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.util.Assert;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import per.vic.attachment.constant.DatabaseType;
import per.vic.attachment.controller.AttachmentApi4ClientController;
import per.vic.attachment.controller.AttachmentController;
import per.vic.attachment.dao.BaseAttachmentDao;
import per.vic.attachment.dao.MysqlAttachmentDao;
import per.vic.attachment.dao.OracleAttachmentDao;
import per.vic.attachment.schedule.AttachmentCleaner;
import per.vic.attachment.service.AttachmentClientService;
import per.vic.attachment.service.AttachmentService;
import per.vic.attachment.service.AttachmentStatusOperationService;
import per.vic.attachment.web.AttachmentClientCheckInterceptor;

/**
 * @description: 附件starter 入口
 * @author: Vic.xu
 * @date: 2019年12月12日 上午9:05:28
 */
@Configuration
@ConditionalOnClass(value = {JdbcTemplate.class})
@ConditionalOnWebApplication
@ConditionalOnExpression("${attachment.enabled:true}")
@EnableConfigurationProperties({AttachmentProperties.class})
@EnableScheduling
public class AttachmentAutoconfigure implements InitializingBean {

    private static Logger logger = LoggerFactory.getLogger(AttachmentAutoconfigure.class);

    /** 作为服务端的判断*/
    private static final String SERVER_CONDITION = "${attachment.type:1}==1";

    /** 作为客户端端的判断*/
    private static final String CLIENT_CONDITION = "${attachment.type:1}==2";

    @Autowired
    AttachmentProperties attachmentProperties;

    private BaseAttachmentDao attachmentDao;

    @Autowired
    private JdbcTemplate jdbcTemplate;


    @Override
    public void afterPropertiesSet() throws Exception {
        checkAttachmentProperties();

    }

    /**
     * 检测必须配置的参数项是否存在:
     */
    private void checkAttachmentProperties() {
        // 作为客户端的时候
        if (attachmentProperties.isClient()) {
            Assert.notNull(attachmentProperties.getServer(), "请配置附件服务端的项目地址attachment.server");
        } else {
            //作为服务端的时候
            if (attachmentProperties.isCheckTable()) {
                Assert.state(attachmentDao.isAttachmentTableExist(), "请先为attachment-starter创建附件表");
            }

            Assert.notNull(attachmentProperties.getVisit(), "请配置附件访问的地址前缀attachment.visit,附件访问的地址根据id生成");
            Assert.notNull(attachmentProperties.getPosition(), "请配置附件存储的位置attachment.position");
            Assert.notNull(attachmentProperties.getBroken(), "请问配置默认的附件的相对地址attachment.broken");
            if (StringUtils.isBlank(attachmentProperties.getHost())) {
                logger.warn("未配置附件访问的主机attachment.host， 请确保当前项目可以直接访问到：当前host + 附件的相对地址");
                /*
                    这种情况 可考虑按如下方式配置
                    web.upload-path=D:/temp/images/
                    springboot.mvc.static-path-pattern=/**
                    spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/static,classpath:/resources/,file:${web.upload-path}
                 */
            }
        }

    }


    /**
     * 调用附件服务端接口的SDK,
     * @return
     */
    @Bean
    @ConditionalOnExpression(CLIENT_CONDITION)
    @ConditionalOnMissingBean
    public AttachmentClientService attachmentClientService() {
        return new AttachmentClientService();
    }


    /**
     * DAO
     */
    @Bean
    @ConditionalOnExpression(SERVER_CONDITION)
    @ConditionalOnMissingBean
    public BaseAttachmentDao attachmentDao() {
        BaseAttachmentDao attachmentDao;
        DatabaseType type = DatabaseType.getByName(attachmentProperties.getDatabase());
        switch (type) {

            case oracle:
                attachmentDao = new OracleAttachmentDao();
                break;
            case mysql:
            default:
                attachmentDao = new MysqlAttachmentDao();
        }
        attachmentDao.setJdbcTemplate(jdbcTemplate);
        this.attachmentDao = attachmentDao;
        return attachmentDao;
    }

    /**
     * 修改附件状态service， 服务端时直接修改数据库，客户端时候则调用服务端API
     * @return
     */
    @Bean
    @ConditionalOnMissingBean
    public AttachmentStatusOperationService attachmentStatusOperationService() {
        return new AttachmentStatusOperationService();
    }

    /**
     * service
     */
    @Bean
    @ConditionalOnExpression(SERVER_CONDITION)
    @ConditionalOnMissingBean
    public AttachmentService attachmentService() {
        return new AttachmentService();
    }

    /**
     * cleaner
     */
    @Bean
    @ConditionalOnExpression(SERVER_CONDITION)
    @ConditionalOnMissingBean
    public AttachmentCleaner attachmentCleaner() {
        return new AttachmentCleaner();
    }

    /**
     * controller
     */
    @Bean
    @ConditionalOnExpression(SERVER_CONDITION)
    @ConditionalOnMissingBean
    public AttachmentController attachmentController() {
        return new AttachmentController();
    }


    /**
     * 为客户端提供API的controller
     */
    @Bean
    @ConditionalOnExpression(SERVER_CONDITION)
    @ConditionalOnMissingBean
    public AttachmentApi4ClientController attachment4ClientController() {
        return new AttachmentApi4ClientController();
    }

    /**
     * 服务端接口 的拦截器配置 检验客户端合法性
     */
    @Configuration
    @ConditionalOnExpression(SERVER_CONDITION)
    static class AttachmentClientCheckInterceptorConfig implements WebMvcConfigurer {

        // 需要拦截的URL
        static final String INTERCEPTOR_PATTERN = "/attachment/temporary/**";

        @Autowired
        private AttachmentProperties attachmentProperties;

        @Bean
        public AttachmentClientCheckInterceptor attachmentClientCheckInterceptor() {
            return new AttachmentClientCheckInterceptor(attachmentProperties);
        }

        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            InterceptorRegistration interceptorRegistration = registry.addInterceptor(attachmentClientCheckInterceptor());
            interceptorRegistration.addPathPatterns(INTERCEPTOR_PATTERN);
        }

    }


}
